import base64
import json
import pickle
import re

from django import http
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import DatabaseError
from django.shortcuts import render, redirect

# Create your views here.
from django.urls import reverse
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import Goods
from apps.index.utlis import get_category
from apps.users.models import User
from utils import constants
from utils.response_code import RETCODE


class LoginView(View):
    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        # 获取参数
        json_data = json.loads(request.body.decode())
        phone = json_data.get("phone")
        password = json_data.get("password")
        ver = json_data.get("ver")

        # 校验参数
        if not all([phone, password]):
            return http.HttpResponseBadRequest('参数不全哦！')
        if not re.match(r'^1[3-9]\d{9}$', phone):
            return http.HttpResponseBadRequest('手机号不对')
        # 3数据库查询
        user = authenticate(username=phone, password=password)
        print(user, 'user')
        # 如果用户不存在
        if user is None:
            print(111)
            return render(request, 'login.html', {'account_errmsg': '用户名或者密码错误'})
        # 实现状态保持
        login(request, user)
        # 设置session存放时间
        if ver:
            print(222)
            request.session.set_expiry(0)
        else:
            print(333)
            request.session.set_expiry(None)  # None默认两周
        # 4返回response对象
        next = request.GET.get('next')
        print(next)
        if next:
            print(444)
            response = http.JsonResponse({'code': 1, 'errmsg': "登录成功", 'url': "127.0.0.1:8000" + next})
            # response = redirect(next)
        else:
            print(555)
            response = http.JsonResponse({'code': 0, 'errmsg': "登录成功"})
            # response = rediret(reverse("index:index"))
        # 设置cookie往前端传递用户名信息
        response.set_cookie('username', user.username, max_age=3600 * 24 * 15)
        # data = {'code': 0, 'errmsg': "登录成功",'url':next}
        return response


class RegisterView(View):
    def get(self, request):
        return render(request, 'register.html')

    def post(self, request):
        json_data = json.loads(request.body.decode())
        phone = json_data.get('phone')
        email = json_data.get('email')
        password = json_data.get('password')
        password1 = json_data.get('password1')
        captcha = json_data.get('captcha')
        uuid = json_data.get('uuid')
        ver = json_data.get("ver")
        # print(phone, 'phone')
        # print(email, 'email')
        # print(password, 'password')
        # print(password1, 'password1')
        # print(captcha, 'captcha')
        # print(ver, 'ver')

        id = uuid.split('=')
        uuid = id[1]
        print(uuid, 'uuid')
        # 校验参数
        if not all([phone, email, password, password1, captcha]):
            print(1111)
            return http.JsonResponse({'code': 1001, 'errmsg': "参数不全哦"})
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.JsonResponse({'code': 1002, 'errmsg': "邮箱格式不正确"})
        if ver != True:
            print(22222)
            return http.JsonResponse({'code': 1002, 'errmsg': "请同意协议"})
        # 校验密码
        if not re.match(r'^[a-zA-Z0-9]{8,20}$', password):
            print(33333)
            return http.JsonResponse({'code': 1001, 'errmsg': "密码格式不对哦"})
        # 校验手机号
        if not re.match(r'^1[3-9]\d{9}$', phone):
            print(444444)
            return http.JsonResponse({'code': 1001, 'errmsg': "手机号不对"})
        # 校验两次密码是否一致
        if password1 != password:
            print(555555)
            return http.JsonResponse({'code': 1001, 'errmsg': "两次密码好像不一致哦"})
        # 连接数据库
        redis_conn = get_redis_connection('code')
        # 从数据库取出图片验证码
        redis_text = redis_conn.get('img_%s' % uuid)
        print(redis_text)
        # 提取验证码的时候要判断验证码是否还存在 或者 是否已过期
        if redis_text is None:
            return http.JsonResponse({'code': 10001, 'errmsg': "验证码失效"})
        # 取出来之后就删除
        try:
            # 删除的是uuid
            redis_conn.delete('img_%s' % uuid)
        except Exception as e:
            print(e)

        # 把从数据库取出来的uuid的值解码
        redis_text = redis_text.decode()
        # 对比
        if redis_text.lower() != captcha.lower():
            return http.JsonResponse({'code': 1001, 'errmsg': '用户输入验证码错误'})

        # 3数据库保存用户信息
        try:
            print(666)
            user = User.objects.create_user(password=password, username=phone, email=email)
            print(user, 'user')
        except DatabaseError as e:
            print(e)
            print(777)
            return http.JsonResponse({'code': .2, 'errmsg': '用户保存失败'})
        # 注册成功后 用户就会自动登录 实现状态保持
        login(request, user)

        # 4返回信息
        # response = redirect(reverse('index:index'))
        # 存储cookie
        # response.set_cookie('username', user.username, max_age=3600 * 24 * 15)

        data = {'code': 0, 'errmsg': "注册成功"}
        return http.JsonResponse(data)


class LogoutView(View):
    """退出功能"""

    def get(self, request):
        print(111)
        # 清除session和cookie
        # 这个是删除所有cookie
        request.session.flush()  # 键和值一起清空
        print('清除session')

        # 获取cookie
        request.COOKIES.get('key')
        logout(request)
        print('退出登录')
        # 退出登录后要回到主页面
        response = redirect(reverse('index:index'))
        # 单独再清除登录时单独塞进去的cookie 因为logout只会清除login方法中值为sessionid的cookie
        response.delete_cookie('username')
        # 返回结果
        return response

        # data = {'code': 0, 'errmsg': "注册成功"}
        # return http.JsonResponse(data)


class UserCollect(LoginRequiredMixin, View):
    """用户我的收藏"""

    def get(self, request):
        """返回用户中心页面"""
        # 返回显示信息
        #

        return render(request, 'user_collect.html')


class UserData(LoginRequiredMixin, View):
    """用户中心 LoginRequiredMixin django自带方法 可以验证用户是否登录"""

    def get(self, request):
        """返回用户中心页面"""
        # 返回显示信息
        # print(request.user.QQ_number, 'game')
        context = {
            'game': request.user.QQ_number,
            'birthday': request.user.birthday,
            'gender': request.user.gender,
            'email': request.user.email
        }
        return render(request, 'user_data.html', context)

    def post(self, request):
        # 获取参数
        game = request.POST.get("game")
        birthday = request.POST.get("birthday")
        gender = request.POST.get("gender")
        # print(game)
        # print(birthday)
        # print(gender)
        # 校验
        if not all([game, birthday, game]):
            return http.HttpResponseBadRequest('参数必须传全哦')

        if len(game) > 10:
            print('游戏号码长度不得长于10位数')
            return http.HttpResponseBadRequest('游戏号码长度不得长于10位数')
        if gender == '1':
            print('是男生')
        elif gender == '2':
            print('是女生')

        # 数据库储存信息
        try:
            print('接下来要往数据库中储存信息了哦')
            # username = User.objects.get('username')
            # print(username)
            # user = User.objects.get(username=13347188734).update()
            request.user.QQ_number = game
            request.user.birthday = birthday
            request.user.gender = gender
            request.user.save()
            print(request.user, 'user')

        except Exception as e:
            print(e)
            print('保存数据库失败了哦')
            return http.HttpResponseBadRequest('保存数据库失败了哦')

        return render(request, 'user_data.html')


class UserOrder(LoginRequiredMixin, View):
    """用户我的订单"""

    def get(self, request):
        """返回用户中心页面"""
        # 返回显示信息
        #

        return render(request, 'user_order.html')


class UserShopping(LoginRequiredMixin, View):
    """用户我的购物车"""

    def get(self, request):
        """展示购物车"""
        # 获取用户
        user = request.user
        # 如果用户存在
        if user.is_authenticated:
            # 连接redis数据库
            redis_conn = get_redis_connection('carts')
            # 获取redis中购物车的数据
            redis_cart = redis_conn.hgetall('carts_%s' % user.id)
            # print('>>>redis_cart>>>', redis_cart)
            # 获取selected的状态
            cart_selected = redis_conn.smembers('selected_%s' % user.id)

            # 将redis中的数据 构造成和cookie中的格式一致，方便统一查询
            cart_dict = {}
            for sku_id, count in redis_cart.items():
                cart_dict[int(sku_id)] = {
                    'count': int(count),
                    'selected': sku_id in cart_selected
                }
        else:
            # 获取cookie
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                # 解密
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}

        # 获取这个cart_dict字典中的所有key
        sku_ids = cart_dict.keys()
        # print('>>>sku_ids>>>', sku_ids)
        # 数据库查询
        skus = Goods.objects.filter(id__in=sku_ids)
        # 定义一个字典
        cart_skus = []
        for sku in skus:
            print(cart_dict.get(sku.id).get('count'))
            print(type(cart_dict.get(sku.id).get('count')))
            print(sku.current_price)
            print(type(sku.current_price))
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'number': cart_dict.get(sku.id).get('count'),
                'selected': cart_dict.get(sku.id).get('selected'),
                'front_image': sku.front_image,
                'now_price': str(sku.current_price),
                'amount': str(eval(sku.current_price) * cart_dict.get(sku.id).get('count'))
            })

        context = {
            'cart_skus': cart_skus
        }

        return render(request, 'Shopping.html', context)

    def post(self, request):
        """添加购物车"""
        # 获取参数
        json_dict = json.loads(request.body.decode())
        # 用户id
        good_id = json_dict.get('good_id')
        # 数量
        number = json_dict.get('number')
        # 姓名
        name = json_dict.get('name')
        current_price = json_dict.get('now_price')
        slave = json_dict.get('slave')
        front_image = json_dict.get('front_image')
        # 是否勾选
        selected = json_dict.get('selected', True)
        print('this is shopping')

        # 校验参数
        if not all([good_id, number]):
            return http.HttpResponseBadRequest('缺少必要参数')
        # 数据库查询 看商品id是否真的存在
        try:
            Goods.objects.get(id=good_id)
        except Goods.DoesNotExist as e:
            print(e)
            return http.HttpResponseBadRequest('商品不存在')

        # 判断count是否为int
        try:
            count = int(number)
        except Exception as e:
            return http.HttpResponseBadRequest('参数count有误')
        # 判断selected是否为bool类型
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseBadRequest('参数selected有误')
        # 添加购物车分为两种 一种是用户已经登录过的 一种是用户未登录
        # 判断用户是否登录
        user = request.user
        print(user)
        if user.is_authenticated:
            # 连接数据库
            redis_conn = get_redis_connection('carts')
            # 创建管道
            p1 = redis_conn.pipeline()

            # 创建购物车
            p1.hincrby('carts_%s' % user.id, good_id, count)
            # 判断是否勾选
            if selected:
                p1.sadd('selected_%s' % user.id, good_id)
            # 执行管道
            p1.execute()

            # 返回响应结果
            return http.JsonResponse({'code': 0, 'errmsg': '添加购物车成功'})
        else:
            # 取出cookie
            cart_str = request.COOKIES.get('carts')
            # 判断这个cookie是否存在
            if cart_str:
                # 把这个字符串解密成python字典
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                # 定义一个字典
                cart_dict = {}
            if good_id in cart_dict:
                # 累加求和
                origin_count = cart_str[good_id]['count']
                count += origin_count
            # 存储数据
            cart_dict[good_id] = {
                'count': (count),
                'selected': selected,
                'name': name,
                'current_price': int(current_price),
                'slave': slave,
            }
            print(cart_dict)
            # 把字典转换为bytes 再把bytes转换为base64的bytes 最后把这个bytes转为字符串
            cookie_cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 创建响应对象
            response = http.JsonResponse({'code': '0', 'errmsg': '添加购物车成了'})
            # 设置cookie
            response.set_cookie('carts', cookie_cart_str, max_age=constants.CARTS_COOKIE_EXPIRES)
            return response

    def put(self, request):
        """
        更新购物车
        :param request:
        :return:
        """
        """修改购物车"""
        # 1 获取请求体中的参数
        json_dict = json.loads(request.body.decode())
        count = json_dict.get('count')
        sku_id = json_dict.get('sku_id')
        selected = json_dict.get('selected', True)
        # 2 校验参数
        if not all([count, sku_id]):
            return http.HttpResponseBadRequest('缺少必要参数')
        try:
            count = int(count)
        except Exception as e:
            return http.HttpResponseBadRequest('count错误')
        try:
            sku = Goods.objects.get(id=sku_id)
        except Goods.DoesNotExist:
            return http.HttpResponseNotFound('sku is not')

        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseBadRequest('selected错误')
        user = request.user
        # 3 判断用户是否登录
        if user.is_authenticated:
            # 4 如果登录 连接redis数据库
            redis_conn = get_redis_connection('carts')
            # 4.1创建管道
            pl = redis_conn.pipeline()
            # 5 修改redis 中的cart和selected数据 hset  h是哈希 set是设置 会把之前的内容会直接覆盖
            pl.hset('carts_%s' % user.id, sku_id, count)
            # 如果用户勾选了
            if selected:
                pl.sadd('selected_%s' % user.id, sku_id)
            else:  # 说明用户取消了勾选 把selected中的数据删除
                pl.srem('selected_%s' % user.id, sku_id)
            # 执行管道
            pl.execute()
            # 创建响应对象
            # 创建响应对象
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'front_image': sku.front_image,
                'current_price': sku.current_price,
                'amount': sku.current_price * count,
            }
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'cart_sku': cart_sku})
        # 6 如果用户未登录 就获取cookie
        else:
            pass
            # 7 判断cookie是否存在 存在就解密 不存在就是一个空的字典
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                cart_dict = {}
            # 修改字典中的数据值
            cart_dict[sku_id] = {
                'count': count,
                'selected': selected
            }

            # 8 加密
            cookie_cart_dict = base64.b64encode(pickle.dumps(cart_dict)).decode()

            # 9 创建响应对象 返回响应
            # 创建响应对象
            cart_sku = {
                'id': sku_id,
                'count': count,
                'selected': selected,
                'name': sku.name,
                'front_image': sku.front_image,
                'current_price': sku.current_price,
                'amount': sku.price * count,
            }
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok', 'cart_sku': cart_sku})
            # 10 设置cookie
            response.set_cookie('carts', cookie_cart_dict, max_age=constants.CARTS_COOKIE_EXPIRES)
            # 返回响应对象
            return response


class CartsSelection(View):
    """购物车全选与反全选"""

    def put(self, request):
        # 1获取参数selected
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get('selected')
        print(selected)
        print(type(selected))

        # 校验参数
        if selected:
            if not isinstance(selected, bool):
                return http.HttpResponseBadRequest('selected参数错误')
        # 判断用户是否登录
        user = request.user
        if user.is_authenticated:
            # 1连接redis数据库
            redis_conn = get_redis_connection('carts')
            # 取出购物车中的数据
            cart_sku_dict = redis_conn.hgetall('carts_%s' % user.id)
            # 取出所有的sku_id
            sku_id_list = cart_sku_dict.keys()
            # 2创建管道
            pl = redis_conn.pipeline()
            # 判断用户选择的全选还是取消全选 *sku_id_list拆包 相当于[3,5]=3,5
            if selected:
                pl.sadd('selected_%s' % user.id, *sku_id_list)
            else:
                pl.srem('selected_%s' % user.id, *sku_id_list)
            # 执行管道
            pl.execute()
            # 返回响应
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})
        else:
            # 获取cookie
            cart_str = request.COOKIES.get('carts')
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '全选成功',"selected_all":bool(selected)})
            # 如果cookie不是空
            if cart_str:
                # 解密
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
                # 循环字典
                for sku_id in cart_dict:
                    # 设置字典中的selected值
                    cart_dict[sku_id]['selected'] = selected
                # 解密
                cookie_dict = base64.b64encode(pickle.dumps(cart_dict)).decode()
                # 设置cookie
                response.set_cookie('carts', cookie_dict, constants.CARTS_COOKIE_EXPIRES)

            return response
